home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / ch_4.3 / xcc / xcc.c < prev    next >
C/C++ Source or Header  |  1999-09-11  |  19KB  |  774 lines

  1. /* 
  2.  * xcc.h
  3.  * 
  4.  * Practical Algorithms for Image Analysis
  5.  * 
  6.  * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
  7.  */
  8.  
  9. /*
  10.  * XC(enter)C(ircular disks)
  11.  *
  12.  * determine, in an efficient manner, (estimates of) center positions 
  13.  * for circular objects by taking advantage of knwoledge about the
  14.  * circular object shape and object size, the latter in the form of 
  15.  * a known radius, R, or mean and variance of the distribution of radii:
  16.  * 
  17.  * speed enhancements derive from two principal sources:
  18.  * -- i) the (vertical) interval, DELTA_i, of the raster scan performed
  19.  *    to locate object boundaries is set in accordance with
  20.  *    the value supplied for D == 2*R (or <D>) so as to sample 
  21.  *    each object in at least n (and at most n+1) successive scans: 
  22.  *    DELTA_i is thus simply given as D/n; n may be adjusted to reflect 
  23.  *    the fidelity of the object (``disk'') contour: for a monodisperse
  24.  *    distribution of perfect binary disks n might be set to 2 for 
  25.  *    greatest gain in computatinal efficiency, while a noisy contour 
  26.  *    might necessitate a higher sampling frequency, or greater n, to 
  27.  *    ensure a better estimate of the center position, derived from a 
  28.  *    set of 2*n (maximally 2*(n+1))  contour points;
  29.  *
  30.  * --ii) assuming circular shapes, the center position is determined
  31.  *    from a set of boundary points, implying an associated complexity
  32.  *    O(N), N denoting the number of object pixels, as opposed to the
  33.  *    O(N**2) dependence of template matching methods
  34.  * 
  35.  */
  36.  
  37. #include "xcc.h"
  38.  
  39. #define    TESTSET        100            /* test data set containing chords */
  40. #define    TOTAL_DISK    TESTSET
  41.  
  42. #undef    DEBUG
  43. #undef  DPRINT
  44. #undef    DBG_MEM
  45.  
  46. #undef    SHOW_ETLL
  47. #undef    CHECK_ETLL
  48. #undef    CHECK_DLL
  49.  
  50. #define    NO_DISPLAY    -1
  51. #define    TERSE        0
  52. #define    VERBOSE        1
  53.  
  54.  
  55. #define    DISPL_PAGE    1
  56. #define    RESET        1
  57. #define    NO_RESET    0
  58.  
  59. #define    BORDER_WIDTH    1          /* zero border width (in pix), default value */
  60. #define    EDGE_FILTER_LEN    5       /* default leng of 1d edge detection filter */
  61. #define    NCH_MIN        2              /* min nof scan lines (chords) per disk */
  62. #define    CONTOUR_COLOR    127
  63. #define    UPDATE_DL    6             /* update disk dia, based on _DL proc disks */
  64.  
  65. #define    OFF        0
  66. #define    ON        1
  67.  
  68.  
  69. #define    F_TO_INT(a)    ( ((a)-(int)(a)>0.5) ? ((int)(a)+1) : ((int)(a)) )
  70.  
  71.  
  72. /*
  73.  * global variables
  74.  */
  75. extern char *optarg;
  76. extern int optind, opterr;
  77.  
  78.  
  79. int WRITE_FILE = 0;
  80. int DISP_MODE = TERSE;          /* VERBOSE, TERSE or NO_DISPLAY */
  81. int TEST_INPUT = 0;
  82. int SCAN_IMG = 1;
  83. int DISPL_DISK_BDY = 1;         /* when set, display convex hull */
  84. int ZB = -1;
  85. int R_DSK = -1;                 /* disk radius estimate supplied ? */
  86. int VERT_SI = -1;               /* vertical scan interval supplied ? */
  87. char *IMG_TYPE = "B";           /* img type: B or G */
  88. int GRAY_LEV = 0;               /* BNRY(0)/GRTN(1) */
  89. int UPDATE_DDIA = 1;            /* when set, update disk dia */
  90.  
  91.  
  92. int INP_FILE_TYPE = -1;         /* input file types */
  93. int TPL = 0;
  94.  
  95. FILE *fpIn, *fpOut;
  96.  
  97. int del_ir;                     /* vertical scan interval */
  98. float drad, ddia;               /* estimated disk radius, diameter */
  99.  
  100.  
  101. /*
  102.  * display disk contours
  103.  */
  104. void
  105. displ_disk_contours (struct linklist *list, Image * imgIO, int value)
  106. {
  107.   struct disk *cdsk;
  108.   int nd;
  109.  
  110.   llhead (list);
  111.   if ((nd = ll_length (list)) != 0) {  /* list not empty */
  112. #ifdef DPRINT
  113.     gprintf (fpOut, "\n...display disk contours\n");
  114. #endif
  115.     do {
  116.       if ((cdsk = (struct disk *) list->clp->item)->Type == Accept) {
  117.  
  118.         draw_circle (cdsk->ctr.x, cdsk->ctr.y, cdsk->rad, imgIO, value);
  119.       }
  120.  
  121.     } while (llnext (list) == True);
  122.   }
  123. #ifdef DPRINT
  124.   else
  125.     gprintf (fpOut, "  list empty\n");
  126. #endif
  127. }
  128.  
  129. /*
  130.  * initialize disk list
  131.  *
  132.  * note: matching function to be set by call to llsetmatch() in code as needed
  133.  */
  134. void
  135. init_dll (struct linklist *disk_list)
  136. {
  137.  
  138.   llzero (disk_list);           /* init empty list */
  139.   llsetsize (sizeof (struct disk), disk_list);
  140. }
  141.  
  142.  
  143. /*
  144.  * initialize edge_tuple list
  145.  *
  146.  * note: matching function to be set by call to llsetmatch() in code as needed
  147.  */
  148. void
  149. init_etll (struct linklist *edge_tuple_list)
  150. {
  151.  
  152.   llzero (edge_tuple_list);     /* init empty list */
  153.   llsetsize (sizeof (struct edge_tuple), edge_tuple_list);
  154. }
  155.  
  156.  
  157.  
  158. /*
  159.  * deallocate memory occupied by links in a list
  160.  */
  161. int
  162. rm_llistlink (struct linklist *list)
  163. {
  164.   int link_count;
  165.  
  166.   link_count = 0;
  167.   llhead (list);
  168.   do {
  169.     lldelete (list);
  170.     link_count++;
  171.  
  172.   } while (list->listlength != 0);
  173.  
  174.   return (link_count);
  175. }
  176.  
  177.  
  178. /*
  179.  * display edge tuple list
  180.  */
  181. void
  182. show_etpl_list (struct linklist *list)
  183. {
  184.   struct edge_tuple *cetpl;
  185.   int ie = 0, ne;
  186.  
  187.   llhead (list);
  188.   if ((ne = ll_length (list)) != 0) {  /* list not empty */
  189. #ifdef DPRINT
  190.     gprintf (fpOut, "\n...list of %d edge tuples\n", ne);
  191. #endif
  192.     do {
  193.       cetpl = (struct edge_tuple *) list->clp->item;
  194. #ifdef DPRINT
  195.       gprintf (fpOut, " (%3d, %3d); status: %2d\n",
  196.                cetpl->cl, cetpl->cr, (int) cetpl->status);
  197.       if ((ie + 1) % 8 == 0) {
  198.         gprintf (fpOut, "\n");
  199.         ie = 0;
  200.       }
  201. #endif
  202.       ie++;
  203.     } while (llnext (list) == True);
  204.   }
  205. #ifdef DPRINT
  206.   else
  207.     gprintf (fpOut, "  list empty\n");
  208. #endif
  209. }
  210.  
  211.  
  212.  
  213. /*
  214.  * display list (terse version)
  215.  */
  216. void
  217. tshow_disk_list (struct linklist *list)
  218. {
  219.   struct disk *cdsk;
  220.   int id = 0, nd;
  221.  
  222.   llhead (list);
  223.   if ((nd = ll_length (list)) != 0) {  /* list not empty */
  224.     gprintf (fpOut, "\n...list of %d disk centers\n", nd);
  225.     do {
  226.       cdsk = (struct disk *) list->clp->item;
  227.       gprintf (fpOut, " (%3d, %3d)", cdsk->ctr.x, cdsk->ctr.y);
  228.       if ((id + 1) % 8 == 0) {
  229.         gprintf (fpOut, "\n");
  230.         id = 0;
  231.       }
  232.       id++;
  233.     } while (llnext (list) == True);
  234.   }
  235.   else
  236.     gprintf (fpOut, "  list empty\n");
  237. }
  238.  
  239.  
  240. /*
  241.  * display list
  242.  */
  243. void
  244. show_disk_list (struct linklist *list)
  245. {
  246.   struct disk *cdsk;
  247.   int id = 0, nd;
  248.   int ich;
  249.  
  250.   llhead (list);
  251.   if ((nd = ll_length (list)) != 0) {  /* list not empty */
  252.     gprintf (fpOut, "\n...list of %d disk structures\n", nd);
  253.     do {
  254.       cdsk = (struct disk *) list->clp->item;
  255.       gprintf (fpOut, "\n   %3d chord(s) (r; cl, cr):\n", cdsk->nch);
  256.       for (ich = 0; ich < cdsk->nch; ich++) {
  257.         gprintf (fpOut, "     (%3d; %3d, %3d)\n",
  258.                  cdsk->chords[ich].r,
  259.                  cdsk->chords[ich].cl,
  260.                  cdsk->chords[ich].cr);
  261.       }
  262.       gprintf (fpOut, "   center: (%3d, %3d)",
  263.                cdsk->ctr.x, cdsk->ctr.y);
  264.       gprintf (fpOut, "...radius: %3d", cdsk->rad);
  265.       gprintf (fpOut, "...status: %d\n", cdsk->Status);
  266.  
  267.     } while (llnext (list) == True);
  268.   }
  269.   else
  270.     gprintf (fpOut, "  list empty\n");
  271. }
  272.  
  273.  
  274. /*
  275.  * update initial estimate of disk diameter
  276.  */
  277. float
  278. update_disk_dia (struct linklist *list)
  279. {
  280.   struct disk *cdsk;
  281.   float odd, dd = (float) 0.0;
  282.   int nd;
  283.  
  284.   odd = ddia;
  285.   dd = (float) 0.0;
  286.   nd = 0;
  287.   llhead (list);
  288.   do {
  289.     cdsk = (struct disk *) list->clp->item;
  290.  
  291.     if (cdsk->nch > 1) {
  292.       dd += (float) 2.0 *cdsk->rad;
  293.       nd++;
  294.     }
  295.  
  296.   } while (llnext (list) == True);
  297.   dd /= (float) nd;
  298.  
  299.   if (fabs ((dd - ddia) / ddia) > 0.1)
  300.     return (dd);
  301.   else
  302.     return (odd);
  303. }
  304.  
  305.  
  306.  
  307.  
  308. /*
  309.  * gprintf() functions:
  310.  * write to std output and, if option WRITE_FILE set, to file wbuf (stream)
  311.  */
  312. void
  313. gprintf (FILE * fpOut, char *fmt,...)
  314. {
  315.   va_list arg_ptr;
  316.  
  317.   va_start (arg_ptr, fmt);
  318.   vprintf (fmt, arg_ptr);
  319.   if (WRITE_FILE == 1)
  320.     vfprintf (fpOut, fmt, arg_ptr);
  321.   va_end (arg_ptr);
  322.  
  323. }
  324.  
  325.  
  326.  
  327. /*
  328.  * error message
  329.  */
  330. void
  331. exitmess (char *prompt, int status)
  332. {
  333.   printf (prompt);
  334.   printf ("\n");
  335.  
  336.   exit (status);
  337. }
  338.  
  339. /*
  340.  * usage of routine
  341.  */
  342. void
  343. usage (char *progname)
  344. {
  345.   progname = last_bs (progname);
  346.   printf ("USAGE: %s inimg outimg [-t file] [-w file] [-s rad] [-n lines]\n", progname);
  347.   printf ("                           [-b] [-z pix] [-i imgtype] [-f len] [-L]\n");
  348.   printf ("\n%s determines, in an efficient manner, (estimates of) center positions\n", progname);
  349.   printf ("for circular objects by taking advantage of knwoledge about the\n");
  350.   printf ("circular object shape and object size, the latter in the form of\n");
  351.   printf ("known radius, R, or mean and variance of the distribution of radii.\n\n");
  352.   printf ("ARGUMENTS:\n");
  353.   printf ("       inimg: input image filename (TIF)\n");
  354.   printf ("      outimg: output image filename (TIF)\n\n");
  355.   printf ("OPTIONS:\n");
  356.   printf ("     -t file: read test input from file fn ( .tpl) -s, -n options disabled\n");
  357.   printf ("     -w file: write disk parameters to file fn.dsk\n");
  358.   printf ("      -s rad: supply estimated (mean) disk radius (in pix)\n");
  359.   printf ("    -n lines: supply min nof scan lines to sample each disk\n");
  360.   printf ("              (must exceed %d)\n", NCH_MIN);
  361.   printf ("          -b: do not display disk bdy\n");
  362.   printf ("      -z pix: zero a border strip of width pix (default: %d)\n", BORDER_WIDTH);
  363.   printf ("      -i str: specify image type, B(BINARY) (default) or G (GRAY) \n");
  364.   printf ("      -f len: specify edge filter len, (odd)l (default: %d)\n", EDGE_FILTER_LEN);
  365.   printf ("          -L: print Software License for this module\n");
  366.   exit (1);
  367. }
  368.  
  369. void
  370. main (int argc, char **argv)
  371. {
  372.   Image *imgIn;
  373.   static char *inp_suffix =
  374.   {".tpl"};                     /* default inp file suffix */
  375.   static char *tpl_type =
  376.   {".tpl"};                     /* suffix for .pdt inp file */
  377.  
  378.   static char *wsuffix =
  379.   {".dsk"};                     /* suffix for output file name */
  380.   static char rdbuf[32], *buf = &rdbuf[0];
  381.   static char wrbuf[32], *wbuf = &wrbuf[0];
  382.   int ic, is;
  383.   int i_arg;
  384.  
  385.   /* list structs */
  386.   struct linklist etll;         /* list of edge tuples on current scan line */
  387.   int ne;
  388.  
  389.   struct linklist dll;          /* disk (linked) list */
  390. #ifdef DEBUG
  391.   struct linklist *cdll;        /* ptr to current dll */
  392. #endif
  393.   int rm_link = 0;
  394.  
  395.  
  396.   int nds;
  397.   int nch;
  398.  
  399.   /* AOI dimensions */
  400.   int ir, ir_base;
  401.   int nrw, ncl;
  402.   int jmin, imin, jmax, imax;
  403.   int left_x, right_x;
  404.   int strip_wdth = BORDER_WIDTH;
  405.   unsigned char *row;
  406.   int nf = EDGE_FILTER_LEN;
  407.   float *ef;
  408.  
  409. /* 
  410.  * cmd line options ( see usage() ):
  411.  */
  412.   static char *optstring = "t:w:s:n:z:bi:f:L";
  413.  
  414.  
  415. /*
  416.  * parse command line
  417.  */
  418.   optind = 3;
  419.   opterr = 1;                   /* give error messages */
  420.  
  421.   if (argc < 2)
  422.     usage (argv[0]);
  423.  
  424.   while ((i_arg = getopt (argc, argv, optstring)) != EOF) {
  425.     switch (i_arg) {
  426.  
  427.     case 't':
  428.       printf ("...option %c: ", i_arg);
  429.       printf (" employ test data in file %s\n", buf = optarg);
  430.       TEST_INPUT = 1;
  431.       SCAN_IMG = 0;
  432.       UPDATE_DDIA = 0;
  433.  
  434.       /* get size of data set from file */
  435.       if ((fpIn = fopen (buf, "r")) == NULL) {
  436.         printf ("\n...could not open input file\n");
  437.         exit (1);
  438.       }
  439.  
  440.       /* strip file suffix and determine file type */
  441.       ic = 0;
  442.       while (*(buf + ic) != '.')
  443.         ic++;
  444.       for (is = 0; is < 4; is++)
  445.         *(inp_suffix + is) = *(buf + ic + is);
  446.  
  447.       if (strncmp (inp_suffix, tpl_type, 4) == 0) {
  448.         INP_FILE_TYPE = TPL;
  449.       }
  450.  
  451.       /* initialize size variables */
  452.       fetch_test_parms (fpIn, &ddia, &del_ir, &nch, &ir_base);
  453.       printf ("\n...test parameters retrieved: ");
  454.       printf (" disk dia: %f\n", ddia);
  455.       printf (" vert scan interval: %3d\n", del_ir);
  456.       printf (" corresp vert scan freq: %3d\n", nch);
  457.  
  458.       R_DSK = 1;
  459.       VERT_SI = 1;
  460.       break;
  461.     case 'w':
  462.       printf ("...option %c: ", i_arg);
  463.       printf (" write disk data to file %s\n",
  464.               wbuf = optarg);
  465.       if ((fpOut = fopen (wbuf, "w")) == NULL) {
  466.         printf ("\n...cannot open %s for writing\n",
  467.                 wbuf);
  468.         exit (1);
  469.       }
  470.       gprintf (fpOut, "...logging params in file %s\n", wbuf);
  471.       WRITE_FILE = 1;
  472.       break;
  473.     case 's':
  474.       printf ("...option %c: ", i_arg);
  475.       if (TEST_INPUT == 0) {
  476.         printf (" supply estimate of disk RADIUS: %f\n",
  477.                 drad = (float) atof (optarg));
  478.         ddia = (float) 2.0 *drad;
  479.         R_DSK = 1;
  480.         if (VERT_SI == -1) {
  481.           nch = NCH_MIN;
  482.           printf ("  -->default vert scan interval: %3d\n",
  483.                   del_ir = F_TO_INT (drad) - 1);
  484.         }
  485.       }
  486.       else
  487.         printf (" TEST_INPUT -- option disabled\n");
  488.       break;
  489.     case 'n':
  490.       printf ("...option %c: ", i_arg);
  491.       if (TEST_INPUT == 0) {
  492.         printf (" set vert scan freq (min scan lns/disk): ");
  493.         printf ("nch = %d\n", nch = atoi (optarg));
  494.         if (R_DSK == -1) {
  495.           printf ("\n...must first supply estimate for (mean) disk radius\n");
  496.           exit (1);
  497.         }
  498.         printf ("  -->implied vert scan interval: %3d\n",
  499.                 del_ir = F_TO_INT (2.0 * drad / (float) nch));
  500.  
  501.         if (nch * del_ir == F_TO_INT (ddia)) {
  502.           nch++;
  503.           printf ("  -->adj vert scan freq: ");
  504.           printf (" max scan lns/dsk: %d\n", nch);
  505.         }
  506.         VERT_SI = 1;
  507.       }
  508.       else
  509.         printf (" TEST_INPUT -- option disabled\n");
  510.       break;
  511.     case 'b':
  512.       printf ("...option %c:", i_arg);
  513.       printf ("  do not display disk boundaries\n");
  514.       DISPL_DISK_BDY = 0;
  515.       break;
  516.     case 'z':
  517.       printf ("...option %c:", i_arg);
  518.       printf (" zero a border strip of width %d\n",
  519.               strip_wdth = atoi (optarg));
  520.       ZB = 1;
  521.       break;
  522.     case 'i':
  523.       printf ("...option %c:", i_arg);
  524.       printf (" process %s image\n", IMG_TYPE = optarg);
  525.       if (strncmp (IMG_TYPE, "B", 1) == 0)
  526.         GRAY_LEV = 0;
  527.       else if (strncmp (IMG_TYPE, "G", 1) == 0)
  528.         GRAY_LEV = 1;
  529.       else
  530.         exitmess ("\n...unknown image type\n", 1);
  531.       break;
  532.     case 'f':
  533.       printf ("...option %c:", i_arg);
  534.       printf (" select edge filter length: ");
  535.       if ((nf = atoi (optarg)) % 2 == 0)
  536.         nf++;
  537.       printf ("%2d\n", nf);
  538.       break;
  539.     case 'L':
  540.       print_sos_lic ();
  541.       exit (0);
  542.     default:
  543.       printf ("\n...unknown condition encountered\n");
  544.       exit (1);
  545.       break;
  546.     }
  547.   }
  548.   if (R_DSK == -1) {
  549.     printf ("\n...must supply estimate for (mean) disk radius\n");
  550.     exit (1);
  551.   }
  552.  
  553.  
  554.  
  555.  
  556. /*
  557.  * Read input image
  558.  */
  559.   imgIn = ImageIn (argv[1]);
  560.  
  561.   if (imgIn->bps == 8 && imgIn->spp == 3) {
  562.     printf ("Got RGB image!!!\nInput image must be Grayscale or B&W!!\n");
  563.     exit (1);
  564.   }
  565.  
  566. /*
  567.  * scan full frame (if AOI desired, supply boundary coordinates here)
  568.  */
  569.   jmin = imin = 0;
  570.   jmax = imgIn->width;
  571.   imax = imgIn->height;
  572.  
  573.   left_x = jmin;
  574.   right_x = jmax - 1;
  575.   ncl = jmax - jmin;
  576.   nrw = imax - imin;
  577.  
  578. #ifdef DEBUG
  579.   printf ("\n...ncl = %d, nrw = %d\n", ncl, nrw);
  580. #endif
  581.  
  582. /*
  583.  *  zero outer border of image (-->select one method)
  584.  */
  585.   if (ZB == 1)
  586.     zero_border (imgIn, strip_wdth);
  587.  
  588.  
  589. /*
  590.  * display parameter settings employing global printf function;
  591.  * open log file
  592.  */
  593.   gprintf (fpOut, "\nparameter settings:\n");
  594.   gprintf (fpOut, "         image type: %s\n", IMG_TYPE);
  595.   gprintf (fpOut, "vert scan interval (del_ir): %3d\n", del_ir);
  596.   gprintf (fpOut, "           disk dia: %f\n", ddia);
  597.  
  598. /*
  599.  * memory allocation
  600.  */
  601.   if ((row = (unsigned char *) calloc (ncl, sizeof (unsigned char))) == NULL)
  602.       exitmess ("mem alloc for row failed", 1);
  603.  
  604.  
  605.   if (TEST_INPUT == 1) {
  606.     gprintf (fpOut, "\n...process test data set in %s\n", buf);
  607.   }
  608.   else if (SCAN_IMG == 1) {
  609.     gprintf (fpOut, "\n...scan image\n");
  610.  
  611.     if (GRAY_LEV == 1) {
  612.       if ((ef = (float *) calloc (nf, sizeof (float))) == NULL)
  613.           exitmess ("mem alloc for edge filter ef failed", 1);
  614.  
  615.       fetch_edge_det (ef, nf);
  616.     }
  617.   }
  618.  
  619.  
  620. /*
  621.  * initialize (empty) lists
  622.  */
  623.   init_etll (&etll);
  624.   init_dll (&dll);
  625.  
  626.  
  627.  
  628. #ifdef DEBUG
  629.   cdll = &dll;
  630.   printf ("\n...structure parameters for disk list:\n");
  631.   printf ("sizeof(struct linklist): %d\n", sizeof (struct linklist));
  632.   printf ("        item length: %d\n", cdll->itemlength);
  633.   printf ("    cur list length: %d\n", cdll->listlength);
  634. #endif
  635.  
  636.  
  637. /*
  638.  * loop over (selected) rows
  639.  *   for each row index: scan row, applying desired (1d) edge filter,
  640.  *   and construct list of edge tuples;
  641.  *
  642.  *   following completion of scan, update disk list by matching the
  643.  *   ``runs'' of ON-pixels, given by the set of edge tuples {yl, yr},
  644.  *   to the those entries in the disk list which remain ACTIVE:
  645.  *   if no match is found, the respective disk entry in the list
  646.  *   is closed (set to INACTIVE) and a new ACTIVE disk is opened 
  647.  *
  648.  *   matching is accmplished by examining ``symmetric'' overlap of
  649.  *   runs in successive scans, as detailed below (see function 
  650.  *   update_dll() )
  651.  */
  652.  
  653.   if (TEST_INPUT == OFF)
  654.     ir_base = strip_wdth + 1;
  655.   ir = ir_base;
  656.   nds = 0;                      /* current number of disks */
  657.   do {
  658.     ne = 0;                     /* nof ON segm (edge tpls) per row */
  659.     init_etll (&etll);
  660.  
  661. /* scan image row */
  662.     if (TEST_INPUT == 1) {
  663.       ne = fetch_test_row (fpIn, &etll);
  664.     }
  665.     else if (SCAN_IMG == 1) {
  666.       getrow (row, ir, imgIn);
  667.  
  668.       if (GRAY_LEV == 1)
  669.         edge_det (row, ncl, ef, nf);
  670. #ifdef DPRINT
  671.       printf ("...about to encode row %d\n", ir);
  672. #endif
  673.       ne = encode_row (row, ncl, &etll, GRAY_LEV);
  674.     }
  675.  
  676. #ifdef SHOW_ETLL
  677.     printf ("\n...row %3d: ", ir);
  678.     show_etpl_list (&etll);
  679. #endif
  680.  
  681.     if (ne > 0) {
  682.       nds += update_disk_list (ir, nch, &dll, &etll);
  683.  
  684. #ifdef CHECK_DLL
  685.       show_disk_list (&dll);
  686. #endif
  687.  
  688.  
  689. /* clear edge tuple list */
  690.       rm_link = rm_llistlink (&etll);
  691.  
  692. #ifdef DPRINT
  693.       printf ("...%d entries removed from edge tuple list\n", rm_link);
  694. #endif
  695.     }
  696.  
  697. /* update initial estimate of disk diameter */
  698.     if ((UPDATE_DDIA == ON) && (ll_length (&dll) >= UPDATE_DL)) {
  699. #ifdef DPRINT
  700.       printf ("\n...update init estimate of disk diameter\n");
  701. #endif
  702.  
  703.       ddia = update_disk_dia (&dll);
  704.  
  705.       del_ir = F_TO_INT (ddia / (float) nch);
  706.       if (nch * del_ir >= (int) ddia)
  707.         nch++;
  708.  
  709. #ifdef DPRINT
  710.       printf ("  -->new estimate of disk dia: %f\n", ddia);
  711.       printf ("  -->new vert scan interval: %3d\n", del_ir);
  712.       printf ("  -->new vert scan freq: %2d\n", nch);
  713. #endif
  714.  
  715.       UPDATE_DDIA = OFF;
  716.     }
  717.  
  718.  
  719.     ir += del_ir;
  720.  
  721.   } while (ir < nrw - (ir_base + 1));
  722.  
  723.  
  724. /*
  725.  * display results
  726.  */
  727. #ifdef DPRINT
  728.   printf ("\n...done with construction of disk list:\n");
  729.  
  730.   if (DISP_MODE == VERBOSE)
  731.     show_disk_list (&dll);
  732.   else if (DISP_MODE == TERSE)
  733.     tshow_disk_list (&dll);
  734. #endif
  735. /*
  736.  * overlay disk contours onto original image
  737.  */
  738.   if (DISPL_DISK_BDY == ON) {
  739.     displ_disk_contours (&dll, imgIn, GRAY);
  740.   }
  741.  
  742.  
  743. /*
  744.  * deallocate memory assigned to lists
  745.  */
  746. #ifdef DPRINT
  747.   printf ("\n...deallocating memory for linked lists\n");
  748.   printf ("    disks:\n");
  749. #endif
  750.   rm_link = rm_llistlink (&dll);
  751. #ifdef DBG_MEM
  752.   printf ("   %d links removed from disk list\n", rm_link);
  753. #endif
  754.  
  755.  
  756. /*
  757.  * deallocate memory and close files
  758.  */
  759.   free (row);
  760.   if (GRAY_LEV == 1)
  761.     free (ef);
  762.  
  763.   if (TEST_INPUT == 1)
  764.     fclose (fpIn);
  765.   if (WRITE_FILE == 1)
  766.     fclose (fpOut);
  767. /*
  768.  * Write the output image
  769.  */
  770.   printf ("...writing image file %s\n", argv[2]);
  771.   ImageOut (argv[2], imgIn);
  772.  
  773. }
  774.